﻿using BootstrapBlazor.Components; 
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Localization;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

using CodeMan.Data.DataServiceBaseExts; 
using CodeMan.Data;
using Microsoft.EntityFrameworkCore;
using CodeMan.Application.Contracts.ClassGens;
using CodeMan.Application.Contracts;
using CodeMan.Application.Contracts.Cache;

namespace Microsoft.Extensions.DependencyInjection
{
    /// <summary>
    /// BootstrapBlazor 服务扩展类
    /// </summary>
    public static class CodeManServiceCollectionExtensions
    {
        /// <summary>
        /// 增加 PetaPoco 数据库操作服务
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddTableDemoDataCodeManService(this IServiceCollection services)
        {
            services.AddScoped(typeof(IDataService<>), typeof(TableDemoDataService<>));
            //services.AddScoped(typeof(IDataService<ClassGenDTOCreateUpdate>), typeof(ClassGenDTOTableDemoDataService));

            return services;
        }
    }
    /// <summary>
    /// 演示网站示例数据注入服务实现类
    /// </summary>
    public class TableDemoDataService<TModel> : DataServiceBase<TModel> where TModel : class, new()
    {
        private static readonly ConcurrentDictionary<Type, Func<IEnumerable<TModel>, string, SortOrder, IEnumerable<TModel>>> SortLambdaCache = new();

        public List<TModel> Items { get; set; }

        private IStringLocalizer<TModel> Localizer { get; set; }

        public TableDemoDataService(IStringLocalizer<TModel> localizer)
        {
            Localizer = localizer;

        }

        /// <summary>
        /// 查询操作方法
        /// </summary>
        /// <param name="options"></param>
        /// <returns></returns>
        public override Task<QueryData<TModel>> QueryAsync(QueryPageOptions options)
        {
            // 此处代码实战中不可用，仅仅为演示而写防止数据全部被删除
            if (Items == null)
            {
                //Items = new List<TModel>();//FooDemo.GenerateFoo(Localizer).Cast<TModel>().ToList();
                Items = new List<TModel>();
            }

            var items = Items.AsEnumerable();
            var isSearched = false;

            // 处理高级查询
            switch (options.SearchModel)
            {
                case FooDemo:
                    isSearched = (options.SearchModel as FooDemo).Query<TModel>(items); 
                    break;
                case ClassGenDTO:
                    isSearched = (options.SearchModel as ClassGenDTO).Query<TModel>(items);
                    break;
                case ClassAttributeDTO:
                    isSearched = (options.SearchModel as ClassAttributeDTO).Query<TModel>(items);
                    break;
                default:
                    break;
            }

            if (options.Searchs.Any())
            {
                // 针对 SearchText 进行模糊查询
                items = items.Where(options.Searchs.GetFilterFunc<TModel>(FilterLogic.Or));
            }

            // 过滤
            var isFiltered = false;
            if (options.Filters.Any())
            {
                items = items.Where(options.Filters.GetFilterFunc<TModel>());
                isFiltered = true;
            }

            // 排序
            var isSorted = false;
            if (!string.IsNullOrEmpty(options.SortName))
            {
                Func<IEnumerable<TModel>, string, SortOrder, IEnumerable<TModel>> invoker = null;
                // 外部未进行排序，内部自动进行排序处理
                switch (options.SearchModel)
                {
                    case FooDemo:
                        invoker = SortLambdaCache.GetOrAdd(typeof(FooDemo), key => LambdaExtensions.GetSortLambda<TModel>().Compile());
                        break;
                    case ClassGenDTO:
                        invoker = SortLambdaCache.GetOrAdd(typeof(ClassGenDTO), key => LambdaExtensions.GetSortLambda<TModel>().Compile());
                        break;
                    case ClassAttributeDTO:
                        invoker = SortLambdaCache.GetOrAdd(typeof(ClassAttributeDTO), key => LambdaExtensions.GetSortLambda<TModel>().Compile());
                        break;
                    default:
                        break;
                }
                if (invoker != null)
                {
                    items = invoker(items, options.SortName, options.SortOrder);
                    isSorted = true;
                }

            }

            var total = items.Count();

            return Task.FromResult(new QueryData<TModel>()
            {
                Items = items.Skip((options.PageIndex - 1) * options.PageItems).Take(options.PageItems).ToList(),
                TotalCount = total,
                IsFiltered = isFiltered,
                IsSorted = isSorted,
                IsSearch = isSearched
            });
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public Task<bool> SaveAsync(TModel model)
        {
            var ret = false;

            switch (model)
            {
                case FooDemo:
                    ret = (model as FooDemo).Save<TModel>(Items);
                    break;
                case ClassGenDTO:
                    ret = (model as ClassGenDTO).Save<TModel>(Items);
                    break;
                case ClassAttributeDTO:
                    ret = (model as ClassAttributeDTO).Save<TModel>(Items);
                    break;
                default:
                    break;
            }
            return Task.FromResult(ret);
        }

        public override Task<bool> DeleteAsync(IEnumerable<TModel> models)
        {
            foreach (var model in models)
            {
                Items?.Remove(model);
            }

            return base.DeleteAsync(models);
        }
    }


    public class ClassGenDTOTableDemoDataService : TableDemoDataService<ClassGenDTO>
    {
        public ClassGenDTOTableDemoDataService(IStringLocalizer<ClassGenDTO> localizer):base(localizer)
        {
            base.Items = GCacheData.classDTOsLst;
        }
    }
}
